﻿using Basic.FlowCollect;
using Basic.FlowLocalEvent.Model;
using Basic.FlowModel.DB;
using Basic.FlowModel.Node;
using Basic.FlowModel.NodeMsg;
using Basic.FlowModel.NodeRoute;
using Basic.FlowRemoteModel;
using Basic.FlowRemoteModel.Flow.Model;
using Basic.FlowService.Interface;
using Basic.FlowService.Model.Node;
using WeDonekRpc.Helper;

namespace Basic.FlowService.Extend
{
    internal class FlowEnableService : IFlowEnableService
    {
        private readonly IFlowCollect _Flow;
        private readonly IFlowNodeCollect _Node;
        private readonly INodeMsgCollect _NodeMsg;
        private readonly INodeRouteCollect _NodeRoute;

        public FlowEnableService ( IFlowCollect flow,
            IFlowNodeCollect node,
            INodeMsgCollect nodeMsg,
            INodeRouteCollect nodeRoute )
        {
            this._Flow = flow;
            this._Node = node;
            this._NodeMsg = nodeMsg;
            this._NodeRoute = nodeRoute;
        }
        public bool CheckFlow ( long flowId, out ErrorNode[] error )
        {
            this._flow = this._Flow.Get(flowId);
            return this._CheckFlow(out error);
        }
        private Dictionary<long, long[]> _routes;
        private DBFlowList _flow;
        private NodeCheck[] _nodes;
        private void _CheckNode ( NodeCheck node, List<ErrorNode> errors )
        {
            if ( node.NodeType == FlowNodeType.开始节点 )
            {
                if ( !this._routes.ContainsKey(node.Id) )
                {
                    errors.Add(new ErrorNode
                    {
                        Id = node.Id,
                        Type = "link",
                        Error = "开始节点，连线存在错误!"
                    });
                }
                return;
            }
            else if ( node.NodeType == FlowNodeType.结束节点 )
            {
                if ( !this._routes.IsExists(a => a.Value.Contains(node.Id)) )
                {
                    errors.Add(new ErrorNode
                    {
                        Id = node.Id,
                        Type = "link",
                        Error = "结束节点，连线存在错误!"
                    });
                }
                return;
            }

            if ( node.AuditButton == FlowAuditButton.未设定 )
            {
                errors.Add(new ErrorNode
                {
                    Id = node.Id,
                    Type = "node",
                    Error = "节点：" + node.NodeName + "，审核按钮未设定!"
                });
            }
            if ( node.OutCondition == FlowOutCondition.指定子流程通过 )
            {
                if ( node.OutWaitNodeId.HasValue && !this._nodes.IsExists(a => a.Id == node.OutWaitNodeId.Value) )
                {
                    errors.Add(new ErrorNode
                    {
                        Id = node.Id,
                        Type = "node",
                        Error = "节点：" + node.NodeName + "，出方向配置存在错误，指定的子节点未找到!"
                    });
                }
                else if ( !node.OutWaitNodeId.HasValue )
                {
                    errors.Add(new ErrorNode
                    {
                        Id = node.Id,
                        Type = "node",
                        Error = "节点：" + node.NodeName + "，出方向配置存在错误，未配置指定的子节点!"
                    });
                }
            }
            if ( ( FlowAuditButton.退回 & node.AuditButton ) == FlowAuditButton.退回 )
            {
                if ( node.BackNodeId.HasValue && !this._nodes.IsExists(a => a.Id == node.BackNodeId.Value) )
                {
                    errors.Add(new ErrorNode
                    {
                        Id = node.Id,
                        Type = "node",
                        Error = "节点：" + node.NodeName + "，退回的节点未找到!"
                    });
                }
            }
            if ( !node.IntoFormula.IsNull() && !node.IntoFormula.TrueForAll(a => this._nodes.IsExists(b => b.Id == a.NodeId && b.FormId.GetValueOrDefault(this._flow.DefFormId.Value) == a.FormId)) )
            {
                errors.Add(new ErrorNode
                {
                    Id = node.Id,
                    Type = "formula",
                    Error = "节点：" + node.NodeName + " 进入条件公式存在错误!"
                });
            }

            if ( !this._routes.IsExists(c => c.Value.Contains(node.Id)) || !this._routes.ContainsKey(node.Id) )
            {
                errors.Add(new ErrorNode
                {
                    Id = node.Id,
                    Type = "link",
                    Error = "节点：" + node.NodeName + "，连线存在错误!"
                });
            }
        }
        private bool _CheckFlow ( out ErrorNode[] error )
        {
            this._nodes = this._Node.Gets<NodeCheck>(this._flow.Id);
            this._routes = this._NodeRoute.Gets<RouteBase>(this._flow.Id).GroupBy(a => a.NodeId).ToDictionary(a => a.Key, a => a.Select(c => c.ToNodeId).ToArray());
            NodeMsgCheck[] msgs = this._NodeMsg.Gets<NodeMsgCheck>(this._flow.Id);
            List<ErrorNode> errors = new List<ErrorNode>();
            Dictionary<long, NodeRelation> relation = new Dictionary<long, NodeRelation>();
            List<long> beginId = new List<long>();
            this._nodes.ForEach(c =>
            {
                if ( c.NodeType == FlowNodeType.开始节点 || c.NodeType == FlowNodeType.子流程 )
                {
                    beginId.Add(c.Id);
                }
                relation.Add(c.Id, new NodeRelation
                {
                    Id = c.Id,
                    Name = c.NodeName,
                    NodeType = c.NodeType,
                    ToNode = this._routes.GetValueOrDefault(c.Id)
                });
                this._CheckNode(c, errors);
                NodeMsgCheck[] list = msgs.FindAll(a => a.NodeId == c.Id && a.ReceiveRange == FlowMsgReceiveRange.指定节点审批人);
                if ( list.Length > 0 )
                {
                    list.ForEach(a =>
                    {
                        if ( !a.ToNodeId.IsNull() || !a.ToNodeId.TrueForAll(b => this._nodes.IsExists(c => c.Id == b)) )
                        {
                            errors.Add(new ErrorNode
                            {
                                Id = c.Id,
                                Type = "msg",
                                Error = "节点：" + c.NodeName + "，抄送" + a.MsgType.ToString() + "消息配置存在错误!"
                            });
                        }
                    });
                }
            });
            List<long> repeats = new List<long>(relation.Count);
            beginId.ForEach(a =>
            {
                List<long> ids = new List<long>();
                NodeRelation node = relation[a];
                if ( !this._CheckNodeIsEnd(node, relation, Array.Empty<long>(), ids, out NodeRelation err) )
                {
                    errors.Add(new ErrorNode
                    {
                        Id = err.Id,
                        Type = "link",
                        Error = "节点：" + err.Name + "，无结束点!"
                    });
                }
                if ( ids.Any(c => repeats.Contains(c)) )
                {
                    errors.Add(new ErrorNode
                    {
                        Id = node.Id,
                        Type = "link",
                        Error = "节点：" + node.Name + "，和其它子流程存在交集!"
                    });
                }
                repeats.AddRange(ids);
            });
            if ( errors.Count == 0 )
            {
                error = null;
                return true;
            }
            error = errors.GroupBy(a => new
            {
                a.Id,
                a.Type
            }).Select(a => new ErrorNode
            {
                Id = a.Key.Id,
                Type = a.Key.Type,
                Error = string.Join(" ", a.Select(b => b.Error).Distinct())
            }).ToArray();
            return errors.Count == 0;
        }
        private bool _CheckNodeIsEnd ( NodeRelation node, Dictionary<long, NodeRelation> relationDic, long[] repeats, List<long> nodeId, out NodeRelation err )
        {
            if ( node.NodeType == FlowNodeType.结束节点 )
            {
                err = null;
                return true;
            }
            nodeId.Add(node.Id);
            if ( node.ToNode.IsNull() )
            {
                err = node;
                return false;
            }
            return this._CheckToNode(node, relationDic, repeats.Add(node.Id), nodeId, out err);
        }
        private bool _CheckToNode ( NodeRelation relation, Dictionary<long, NodeRelation> relationDic, long[] repeats, List<long> nodeId, out NodeRelation err )
        {
            NodeRelation error = null;
            bool isEnd = false;
            if ( !relation.ToNode.TrueForAll(c =>
            {
                if ( repeats.Contains(c) )
                {
                    return true;
                }
                NodeRelation node = relationDic[c];
                if ( node.NodeType == FlowNodeType.子流程 )
                {
                    return true;
                }
                else if ( this._CheckNodeIsEnd(node, relationDic, repeats, nodeId, out error) )
                {
                    isEnd = true;
                    return true;
                }
                return false;
            }) )
            {
                err = error;
                return false;
            }
            if ( isEnd )
            {
                err = null;
                return true;
            }
            err = relation;
            return false;
        }

        public bool Enable ( long flowId, out ErrorNode[] error )
        {
            this._flow = this._Flow.Get(flowId);
            if ( this._flow.Status == FlowStatus.启用 )
            {
                error = null;
                return true;
            }
            else if ( !this._flow.DefFormId.HasValue )
            {
                throw new ErrorException("flow.def.form.null");
            }
            else if ( !this._CheckFlow(out error) )
            {
                return false;
            }
            NodeSet[] sets = this._GetNodeSet();
            if ( this._Flow.Enable(this._flow, sets) )
            {
                new FlowEvent(this._flow).AsyncSend("Enable");
                return true;
            }
            return false;
        }
        private NodeSet[] _GetNodeSet ()
        {
            List<NodeSet> nodeSet = new List<NodeSet>();
            NodeCheck node = this._nodes.Find(a => a.NodeType == FlowNodeType.开始节点);
            nodeSet.Add(new NodeSet
            {
                Id = node.Id,
                RootId = node.Id,
                NodeLvl = 1,
            });
            Dictionary<long, NodeCheck> nodeDic = this._nodes.ToDictionary(a => a.Id, a => a);
            this._LoadNodeSet(node.Id, node.Id, 2, nodeDic, nodeSet);
            return nodeSet.ToArray();
        }
        private void _LoadNodeSet ( long nodeId, long rootId, int lvl, Dictionary<long, NodeCheck> nodeDic, List<NodeSet> nodeSet )
        {
            if ( !this._routes.TryGetValue(nodeId, out long[] toId) )
            {
                return;
            }
            toId.ForEach(c =>
            {
                NodeCheck t = nodeDic[c];
                if ( t.NodeType == FlowNodeType.子流程 )
                {
                    nodeSet.Add(new NodeSet
                    {
                        Id = c,
                        NodeLvl = lvl,
                        RootId = c,
                    });
                    this._LoadNodeSet(c, c, lvl + 1, nodeDic, nodeSet);
                }
                else
                {
                    nodeSet.Add(new NodeSet
                    {
                        Id = c,
                        NodeLvl = lvl,
                        RootId = rootId,
                    });
                    this._LoadNodeSet(c, rootId, lvl + 1, nodeDic, nodeSet);
                }
            });

        }
    }
}
